#define EPSILON.001
#define MAX_DIST 1000.
// 用更大的迭代次数保证最远处不隆起
#define MAX_ITER 200

// 不用sin的随机数，因为是无理数在显卡上渲染后会造成不连续的情况。
// float hash12(in vec2 st){
  //   vec3 p3=fract(vec3(st.xyx)*.1031);
  //   p3+=dot(p3,p3.yzx+33.33);
  //   return fract((p3.x+p3.y)*p3.z);
// }
float hash12(in vec2 p){
  vec2 p2=55.1876653*fract(p*10.1321513);
  return fract((p2.x+p2.y)*p2.x*p2.y);
}

vec3 noise(in vec2 st){
  vec2 i=floor(st);
  vec2 f=fract(st);
  
  // Four corners in 2D of a tile
  float a=hash12(i);
  float b=hash12(i+vec2(1.,0.));
  float c=hash12(i+vec2(0.,1.));
  float d=hash12(i+vec2(1.,1.));
  
  // Cubic Hermine Curve.  Same as SmoothStep()
  vec2 u=f*f*(3.-2.*f);
  // Mix 4 coorners percentages
  
  // 设置个梯度
  vec2 du=6.*u*(1.-u);
  
  return vec3(a+(b-a)*u.x*(1.-u.y)+(c-a)*(1.-u.x)*u.y+(d-a)*u.x*u.y,du*(vec2(b-a,c-a)+(a-b-c+d)*u.yx));
}

vec2 fixUV(vec2 cood){
  return(2.*cood.xy-iResolution.xy)/min(iResolution.x,iResolution.y);
}

mat2 mat=mat2(.6,-.8,.8,.6);

float groundH(vec2 x){
  vec2 p=.003*x;
  float a=0.;
  float b=1.;
  vec2 d=vec2(0);
  for(int i=0;i<16;i++){
    vec3 n=noise(p);
    d+=n.yz;
    a+=b*n.x/(1.+dot(d,d));
    p=mat*p*2.;
    b*=.5;
  }
  return 120.*a;
}

float ground(vec2 x){
  vec2 p=.003*x;
  float a=0.;
  float b=1.;
  vec2 d=vec2(0);
  for(int i=0;i<8;i++){
    vec3 n=noise(p);
    d+=n.yz;
    a+=b*n.x/(1.+dot(d,d));
    p=mat*p*2.;
    b*=.5;
  }
  return 120.*a;
}

float groundL(vec2 x){
  vec2 p=.003*x;
  float a=0.;
  float b=1.;
  vec2 d=vec2(0);
  for(int i=0;i<3;i++){
    vec3 n=noise(p);
    d+=n.yz;
    a+=b*n.x/(1.+dot(d,d));
    p=mat*p*2.;
    b*=.5;
  }
  return 120.*a;
}

float rayMarch(vec3 ro,vec3 rd,float tmin,float tmax){
  float t=0.;
  for(int i=0;i<MAX_ITER;i++){
    vec3 p=ro+t*rd;
    float h=p.y-ground(p.xz);
    // EPSILON * t 设置EPSILON精度由近到远变低，提高渲染效率
    if(abs(h)<EPSILON*t||t>tmax){
      break;
    }
    // t+=h;
    // 解决拉伸后瑕疵
    t+=.4*h;
  }
  return t;
}

float softShadow(vec3 ro,vec3 rd,float dis){
  float minStep=clamp(.01*dis,.5,50.);
  float res=1.;
  float t=.001;
  for(int i=0;i<80;i++){
    vec3 p=ro+t*rd;
    float h=p.y-ground(p.xz);
    res=min(res,8.*h/t);
    t+=max(minStep,h);
    if(res<.001||p.y>200.){
      break;
    }
  }
  return clamp(res,0.,1.);
}

vec3 calcNorm(vec3 p,float t){
  vec2 epsilon=vec2(.001*t,0);
  return normalize(vec3(
      groundH(p.xz-epsilon.xy)-groundH(p.xz+epsilon.xy),
      2.*epsilon.x,
      groundH(p.xz-epsilon.yx)-groundH(p.xz+epsilon.yx)
    )
  );
}

mat3 setCamera(vec3 ro,vec3 target,float cr){
  vec3 z=normalize(target-ro);
  vec3 up=normalize(vec3(sin(cr),cos(cr),0));
  vec3 x=cross(z,up);
  vec3 y=cross(x,z);
  return mat3(x,y,z);
}

vec3 render(vec2 uv){
  vec3 col=vec3(0.);
  float an=iTime*.01;
  an=0.;
  float r=500.;
  vec2 pos2d=vec2(r*sin(an),r*cos(an));
  float h=groundL(pos2d)+20.;
  vec3 ro=vec3(pos2d.x,h,pos2d.y);
  // vec3 target=vec3(0,0,10);
  vec3 target=vec3(r*sin(an+.01),h,r*cos(an+.01));
  mat3 cam=setCamera(ro,target,0.);
  
  float fl=1.;
  vec3 rd=normalize(cam*vec3(uv,fl));
  
  float tmin=.01;
  float tmax=MAX_DIST;
  
  float maxh=200.;
  float tp=(maxh-ro.y)/rd.y;
  if(tp>0.){
    if(rd.y>0.){
      tmax=min(tp,tmax);
    }else{
      tmin=max(tp,tmin);
    }
  }
  
  float t=rayMarch(ro,rd,tmin,tmax);
  
  vec3 sunLight=normalize(vec3(.8,.5,-.2));
  float sundot=clamp(dot(rd,sunLight),0.,1.);
  if(t>tmax){
    // 画天空
    col=vec3(.3,.5,.85)-rd.y*rd.y*.5;
    col=mix(col,.85*vec3(.7,.75,.85),pow(1.-max(rd.y,0.),4.));
    // 画太阳
    col+=.25*vec3(1.,.7,.4)*pow(sundot,5.);
    col+=.25*vec3(1.,.8,.6)*pow(sundot,64.);
    col+=.25*vec3(1.,.8,.6)*pow(sundot,512.);
  }else{
    vec3 p=ro+t*rd;
    vec3 n=calcNorm(p,t);
    vec3 difColor=vec3(.67,.57,.44);
    col=.5*difColor;
    
    vec3 lin=vec3(0.);
    
    float dif=clamp(dot(sunLight,n),0.,1.);
    float sh=softShadow(p+.01*sunLight,sunLight,t);
    // lin+=dif*vec3(sh,sh*sh*.5+.5*sh,sh*sh*.8+.2*sh);
    // 加环境光
    float amb=.5*clamp(.5+.5*n.y,0.,1.);
    lin+=dif*vec3(2.,1.5,1.)*vec3(sh,sh*sh*.5+.5*sh,sh*sh*.8+.2*sh);
    lin+=amb;
    
    col*=lin;
    //加雾气
    col=mix(col,.65*vec3(.5,.75,1.),1.-exp(-pow(.002*t,1.5)));
  }
  
  // return sqrt(col);
  return col;
}

void mainImage(out vec4 fragColor,in vec2 fragCoord){
  vec2 uv=fixUV(fragCoord);
  vec3 color=render(uv);
  fragColor=vec4(color,1.);
}